package com.starview.star.operators.pio.runtime;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;

import com.starview.platform.data.IFunction;
import com.starview.platform.data.IValue;
import com.starview.platform.data.value.Factory;
import com.starview.platform.data.value.IntWrap;

public class PrimitiveIOBindings {

  private static StarCompletionHandler<Integer> ch_Integer =
    new StarCompletionHandler<Integer>(new IntegerConverter(), IntWrap.nonIntegerEnum);

  /*
    public static AsynchronousFileChannel _open_file(String path) // options
    {
    try {
    return AsynchronousFileChannel.open(Paths.get(path));
    } catch (Exception e) {
    return null;
    }
    }

    public static void _file_read(AsynchronousFileChannel f, ByteBuffer dst, long pos, IValue callback_v) 
    {
    IFunction callback = (IFunction)callback_v;
    f.read(dst, pos, callback, ch_Integer);
    }
  */

  public static AsynchronousSocketChannel _open_tcp() throws java.io.IOException
  {
    return AsynchronousSocketChannel.open();
  }

  private static StarCompletionHandler<Void> ch_Void =
    new StarCompletionHandler<Void>(new VoidConverter(), Factory.newInteger(0));

  public static void _connect_tcp(AsynchronousSocketChannel ch, InetAddress addr, int port, IValue callback)
  {
    ch.connect(new InetSocketAddress(addr, port), StarCompletionHandler.checkCallbackFunction(callback), ch_Void);
  }

  public static void _socket_close(AsynchronousSocketChannel ch) throws java.io.IOException
  {
    ch.close();
  }

  public static void _socket_read(AsynchronousSocketChannel ch, ByteBuffer bb, IValue callback)
  {
    ch.read(bb, StarCompletionHandler.checkCallbackFunction(callback), ch_Integer);
  }

  public static void _socket_write(AsynchronousSocketChannel ch, ByteBuffer bb, IValue callback)
  {
    ch.write(bb, StarCompletionHandler.checkCallbackFunction(callback), ch_Integer);
  }

  // Server sockets

  public static AsynchronousServerSocketChannel _listen_tcp(InetAddress addr, int port) throws java.io.IOException
  {
    AsynchronousServerSocketChannel s = AsynchronousServerSocketChannel.open();
    s.bind(new InetSocketAddress(addr, port));
    return s;
  }

  public static Void _get_nonValue()
  {
    return null;
  }

  private static StarCompletionHandler<AsynchronousSocketChannel> ch_Socket =
    new StarCompletionHandler<AsynchronousSocketChannel>(new AsynchronousSocketChannelConverter(), Factory.newBinary(null));

  public static void _accept_connection(AsynchronousServerSocketChannel ch, IValue callback)
  {
    ch.accept(StarCompletionHandler.checkCallbackFunction(callback), ch_Socket);
  }
    
  public static void _server_socket_close(AsynchronousServerSocketChannel ch) throws java.io.IOException
  {
    ch.close();
  }

  public static InetAddress _ipv4_address(int b1, int b2, int b3, int b4)
  {
    byte[] bytes = new byte[] { (byte) b1, (byte) b2, (byte) b3, (byte) b4 };
    try {
      return InetAddress.getByAddress(bytes);
    } catch (UnknownHostException e) {
      // "if IP address is of illegal length", which cannot be the case here
      throw new RuntimeException("JDK implementation error.");
    }
  }

  public static InetAddress _ipv6_address(int b1, int b2, int b3, int b4, int b5, int b6, int b7, int b8, int b9, int b10, int b11, int b12, int b13, int b14, int b15, int b16)
  {
    byte[] bytes = new byte[] { (byte) b1, (byte) b2, (byte) b3, (byte) b4, (byte) b5, (byte) b6, (byte) b7, (byte) b8, 
        (byte) b9, (byte) b10, (byte) b11, (byte) b12, (byte) b13, (byte) b14, (byte) b15, (byte) b16 };
    try {
      return InetAddress.getByAddress(bytes);
    } catch (UnknownHostException e) {
      // "if IP address is of illegal length", which cannot be the case here
      throw new RuntimeException("JDK implementation error.");
    }
  }

  public static InetAddress _ip_wildcard_address()
  {
    return null;
  }
  
  public static void _resolve_hostname(String hostname, IValue callback)
  {
    // Though it can take a while, the Java API only has a synchronous call currently:
    IFunction att = StarCompletionHandler.checkCallbackFunction(callback);
    try {
      InetAddress a = InetAddress.getByName(hostname);
      StarCompletionHandler.completed(Factory.newBinary(a), att);
    } catch (UnknownHostException e) {
      StarCompletionHandler.failed(Factory.newBinary(null), e, att);
    }
    
  }
  
  public static String _inet_address_to_string(InetAddress addr)
  {
    if (addr == null)
      return "*"; // wildcard address
    else
      return addr.toString(); // or getHostname()?
  }
  
  
}
